//
//  ARUserManager.swift
//  AquaRaft
//
//  Created by 何启亮 on 2024/3/31.
//

import Foundation
import JKSwiftExtension

/// 用户中心
/// - description: 主要是管理用户登录、用户信息
class ARUserManager {
    
    // MARK: - Public Property
    
    /// 当前登录用户信息
    var userModel: ARUserModel? {
        didSet {
            if let _ = userModel {
                // 发送通知
                NotificationCenter.default.post(name: .userInfoUpdate, object: nil)
            }
        }
    }
    var userId: String?
    var isLogin: Bool = false {
        didSet {
            // 发送通知
            NotificationCenter.default.post(name: .userLoginStateChage, object: nil)
        }
    }
    
    var assentToken: String? {
        get {
            return _token
        }
    }
    
    // MARK: - Private Property
    
    private static let userTokenKey = "AR.userAssentTokenKey"
    private static let userIdKey = "AR.userIdKey"
    
    /// 是否登录中
    /// - note: 鉴于登录操作不是一个多线程的操作，所以就不做线程安全的逻辑
    private var isLoggingIn = false
    
    /// 当前的token
    private var _token: String?
    
    private var appleLoginProvider: ARAppleLoginProvider?
    
    // MARK: - Init
    
    static let shared: ARUserManager = ARUserManager()
    
    private init() {
        self.configManager()
    }
    
    private func configManager() {
        // 获取token
        if let token = UserDefaults.standard.string(forKey: Self.userTokenKey) {
            _token = token
        }
        if let userId = UserDefaults.standard.string(forKey: Self.userIdKey) {
            self.userId = userId
        }
        
        NotificationCenter.default.addObserver(self, selector: #selector(shouldUpldateUserInfoNotificationHandler(_:)), name: .shouldUpdateUserInfo, object: nil)
    }
    
    // MARK: - Login Method
    
    /// 自动登录
    func autoLogin(_ completion: @escaping (Bool, ARUserManagerError?) -> Void) {
        guard let _token = _token, let userId = userId else {
            // 没有登录过 -> 直接返回
            completion(false, ARUserManagerError.tokenIsNilError)
            return
        }
        if isLoggingIn {
            return
        }
        isLoggingIn = true
        // 自动登录
        ARAutoLoginRequest().autoLogin(_token) { [weak self] data, err in
            self?.isLoggingIn = false
            if let err = err {
                completion(false, .apiError(err: err))
                
                // 清除
                self?.clearInfo()
                return
            }
            // 成功 - 获取用户消息
            self?.fetchMineUserInfo(userId, completion: { err in
                if let err = err {
                    completion(false, .apiError(err: err))
                    
                    self?.clearInfo()
                    return
                }
                // 成功
                self?.userId = self?.userModel?.userId
                self?.isLogin = true
                
                if let userId = self?.userId {
                    UserDefaults.standard.set(userId, forKey: Self.userIdKey)
                    UserDefaults.standard.synchronize()
                }
                
                completion(true, nil)
            })
        }
    }
    
    func appleLogin(_ completion: @escaping (Bool, ARUserManagerError?) -> Void) {
        // 苹果登录
        if appleLoginProvider != nil {
            return
        }
        appleLoginProvider = ARAppleLoginProvider()
        appleLoginProvider?.startLogin { [weak self] result in
            self?.appleLoginProvider = nil
            switch result {
            case .cancel:
                completion(false, .userCancelled)
                break
            case .failed(let err):
                completion(false, .apiError(err: err))
                break
            case .success(let token):
                self?._loginRequest(token, type: .apple, completion: completion)
                break
            }
        }
    }
    
    func fastLogin(_ completion: @escaping (Bool, ARUserManagerError?) -> Void) {
        // 判断UUID
        guard let idfa = ARDevice.share.uuidResult.idfa else {
            // 一般不会出现这种情况
            completion(false, .uuidIsNillError)
            return
        }
        
        _loginRequest(idfa, type: .fast, completion: completion)
    }
    
    private func _loginRequest(_ token: String, type: ARLoginRequest.loginType, completion: @escaping (Bool, ARUserManagerError?) -> Void) {
        if isLoggingIn {
            return
        }
        isLoggingIn = true
        ARLoginRequest().login(type, token: token) { [weak self] result in
            self?.isLoggingIn = false
            
            // 这里只会有两种情况
            if case .faild(let err) = result {
                completion(false, .apiError(err: err))
                return
            }
            
            // 只有这两种情况
            if case .success(let loginResponse) = result {
                self?.userId = loginResponse.userInfo.userId
                self?.userModel = loginResponse.userInfo
                self?._token = loginResponse.token
                // token
                UserDefaults.standard.set(loginResponse.token, forKey: Self.userTokenKey)
                UserDefaults.standard.set(loginResponse.userInfo.userId, forKey: Self.userIdKey)
                UserDefaults.standard.synchronize()
                // 发送通知
                self?.isLogin = true
                
                // 登录成功
                ARLogManager.logPage(.loginsuccess)
                
                completion(true, nil)
            }
        }
    }
    
    // MARK: -
    
    func logout(_ completion: @escaping (Error?) -> Void) {
        ARLogoutRequest().logout { [weak self] result in
            if case .faild(let err) = result {
                // 失败
                completion(err)
                return
            }
            
            // 成功
            self?.clearInfo()
            completion(nil)
        }
    }
    
    func deleteAccount(_ completion: @escaping (Error?) -> Void) {
        ARDeleteAccountRequest().delete { [weak self] result in
            if case .faild(let err) = result {
                // 失败
                completion(err)
                return
            }
            
            // 成功
            self?.clearInfo()
            completion(nil)
        }
    }
    
    func fetchMineUserInfo(_ userId: String, completion: @escaping (Error?) -> Void) {
        ARFetchUserInfoRequest().fetchUserInfo(userId) { [weak self] userModel, err in
            if let err = err {
                completion(err)
                return
            }
            guard let userModel = userModel else {
                completion(ARRequestError.modelConvertError(error: nil))
                return
            }
            // 更新userModel
            self?.userModel = userModel
            completion(nil)
        }
    }
    
    // MARK: - Notfication
    
    /// 更新用户信息
    @objc private func shouldUpldateUserInfoNotificationHandler(_ noti: Notification) {
        guard let userId = userId else {
            return
        }
        fetchMineUserInfo(userId) { err in
            // Do nothing...
        }
    }
    
    // MARK: - Helper
    
    /// 清除信息
    private func clearInfo() {
        isLogin = false
        _token = nil
        UserDefaults.standard.removeObject(forKey: Self.userTokenKey)
        UserDefaults.standard.removeObject(forKey: Self.userIdKey)
        UserDefaults.standard.synchronize()
        
        userModel = nil
        userId = nil
    }
    
}

// MARK: - Define

extension Notification.Name {
    
    /// 用户登录状态改变通知
    /// - note:
    /// 在ARUserManager.isLogin属性改变时发送的通知 - 在这个通知只是表明登录状态改变，用户信息不一定有拉取
    static let userLoginStateChage = Notification.Name(rawValue: "AR.userLoginStateChange.notification")
    
    /// 用户信息更新通知
    /// - note:
    /// 获取用户信息接口请求成功 - 修改用户实体时通知
    static let userInfoUpdate = Notification.Name(rawValue: "AR.userInfoUpdate.notification")
    
    /// 通知usermanager更新
    static let shouldUpdateUserInfo = Notification.Name(rawValue: "AR.shouldUpldateUserInfo.notification")
}

/// 登录相关的错误
enum ARUserManagerError: Error, LocalizedError {
    
    /// 自动登录 - token为空
    case tokenIsNilError
    
    /// uuid为空
    case uuidIsNillError
    
    /// 用户取消
    case userCancelled
    
    /// 接口返回的错误
    case apiError(err: Error)
    
    var errorDescription: String? {
        switch self {
        case .tokenIsNilError:
            return ARHelper.localString("Token is nil")
        case .uuidIsNillError:
            return ARHelper.localString("UUID is nil")
        case .userCancelled:
            return ARHelper.localString("User cancelled")
        case .apiError(let err):
            return err.localizedDescription
        }
    }
}
